<?php
declare(strict_types=1);

namespace Dreamcat\ApiDoc\AddSimpleVariableHelper;

use Dreamcat\ApiDoc\Enums\DataType;
use Dreamcat\ApiDoc\Error\GeneratorError;
use Dreamcat\ApiDoc\Popo\ApiDefinition;
use Dreamcat\ApiDoc\Popo\BodyDefinition;
use ReflectionParameter;

/**
 * 添加简单变量的辅助器
 * @author vijay
 */
abstract class AbstractAddSimpleVariableHelper
{
    /**
     * 添加简单变量
     * @param ReflectionParameter $parameter 请求参数代表的控制器参数反射
     * @param BodyDefinition $body 已定义的参数体
     * @param ApiDefinition $apiDefinition 已定义的接口文档
     * @param string|null $path 路径
     * @return ApiDefinition 完善后的接口文档
     */
    public function addSimpleVariable(
        ReflectionParameter $parameter,
        BodyDefinition $body,
        ApiDefinition $apiDefinition,
        ?string $path
    ): ApiDefinition {
        switch ($body->getDataType()->getValue()) {
            case DataType::OBJECT:
            case DataType::MAP:
                break;
            default:
                if ($path === null) {
                    $path = $parameter->name;
                }
        }
        /** @var BodyDefinition[] $list */
        $list = [];
        if ($path === null) {
            foreach ($body->getObjectProperties() as $item) {
                $list[] = $item;
            }
        } else {
            $body->setField($path);
            $list[] = $body;
        }
        foreach ($list as $bodyDefinition) {
            $this->checkField($bodyDefinition->getField());
            $this->checkBodyDefinition($bodyDefinition);
            $apiDefinition = $this->addDefinition($apiDefinition, $bodyDefinition);
        }
        return $apiDefinition;
    }

    /**
     * 检查变量路径是否合法
     * @param string $field 路径
     * @return void
     * @throws GeneratorError
     */
    protected function checkField(string $field): void
    {
        if (str_contains($field, "/")) {
            throw new GeneratorError("{$this->getVariableName()} 不支持多级路径 {$field}", GeneratorError::VAR_PATH_CANT_MUL);
        }
    }

    /**
     * 变量所属的名称，比如 Header、Cookie 等
     * @return string
     */
    abstract protected function getVariableName(): string;

    /**
     * 将参数定义添加到文档中
     * @param ApiDefinition $apiDefinition 已定义的接口文档
     * @param BodyDefinition $definition 已定义的参数体
     * @return ApiDefinition 完善后的接口文档
     */
    abstract protected function addDefinition(
        ApiDefinition $apiDefinition,
        BodyDefinition $definition
    ): ApiDefinition;

    /**
     * 检查变量是否合法
     * @param BodyDefinition $bodyDefinition 已定义的参数体
     * @return void
     */
    protected function checkBodyDefinition(BodyDefinition $bodyDefinition): void
    {
        if (!$bodyDefinition->getDataType()->isScala()) {
            throw new GeneratorError(
                "{$this->getVariableName()} 只能使用标量，不支持 {$bodyDefinition->getDataType()->getValue()}",
                GeneratorError::VAR_MUST_SCALA
            );
        }
    }
}

# end of file
